package com.xiaoniu.workflow.controller;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.spring.boot.app.App;
import org.flowable.task.api.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.xiaoniu.workflow.enums.CurrResultEnum;
import com.xiaoniu.workflow.http.request.CompleteProcessReq;
import com.xiaoniu.workflow.http.request.StartProcessReq;
import com.xiaoniu.workflow.http.request.SubmitProcessReq;
import com.xiaoniu.workflow.http.response.CurrentTaskResp;
import com.xiaoniu.workflow.http.response.StartProcessResp;
import com.xiaoniu.workflow.type.VerificationType;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping(value = "api/workflow", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class WorkFlowController {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;	

	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private ProcessEngine processEngine;

	@Autowired
	private HistoryService historyService;
	

	/**
	 * 流程的部署
	 */
	@RequestMapping(value = "/deploy", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public void deploy() {
		// 定义的文件信息的流读取
		InputStream inputStream = App.class.getClassLoader().getResourceAsStream("processes/aio_apply_process_v1.3.bpmn");
		// 流程定义的分类
		String category = "shareniu_addInputStream";
		String resourceName = "processes/aio_apply_process_v1.3.bpmn";
		// 构造DeploymentBuilder对象
		DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().category(category)
				.addInputStream(resourceName, inputStream);
		// 部署
		Deployment deploy = deploymentBuilder.deploy();
		System.out.println(deploy);
	}

	/**
	 * 生成流程图
	 *
	 * @param processId
	 *            任务ID
	 */
	@RequestMapping(value = "processDiagram")
	public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
		ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

		// 流程走完的不显示图
		if (pi == null) {
			return;
		}
		Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
		// 使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
		String InstanceId = task.getProcessInstanceId();
		List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(InstanceId).list();

		// 得到正在执行的Activity的Id
		List<String> activityIds = new ArrayList<>();
		List<String> flows = new ArrayList<>();
		for (Execution exe : executions) {
			List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
			activityIds.addAll(ids);
		}

		// 获取流程图
		BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
		ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
		ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
		InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows,
				engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(),
				engconf.getClassLoader(), 1.0);
		OutputStream out = null;
		byte[] buf = new byte[1024];
		int legth = 0;
		try {
			out = httpServletResponse.getOutputStream();
			while ((legth = in.read(buf)) != -1) {
				out.write(buf, 0, legth);
			}
		} finally {
			if (in != null) {
				in.close();
			}
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * 启动流程接口
	 * 
	 * @param startProcessReq
	 * @return
	 */
	@PostMapping(value = "/startProcess", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Object> startProcess(@Valid @RequestBody StartProcessReq startProcessReq) {
		String businessKey=startProcessReq.getBusinessKey();
		Map<String, Object> map = new HashMap<String, Object>();
		 //检查流程是否已经启动，在历史记录中查找business key
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .list();
        if (!CollectionUtils.isEmpty(historicProcessInstances)) {
        	logger.error("当前业务编号：{}已经使用，不能重复使用！", businessKey);
			map.put("ret", "10400030");
			map.put("msg", "当前业务编号：" + businessKey + "已经使用过，不能重复使用！");
			return ResponseEntity.ok(map);
        }
        //启动流程
        ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
        Map<String, Object> vars = new HashMap<String, Object>();
        vars.put("isovertime", startProcessReq.getIsovertime());
        vars.put("productId", startProcessReq.getProductId());// 写死一个值
        processInstanceBuilder
                .businessKey(startProcessReq.getBusinessKey())
                .processDefinitionKey(startProcessReq.getProcessDefKey())
                .variables(vars);
        ProcessInstance instance = processInstanceBuilder.start();
        //获取当前节点taskId
        Task currentTask = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();
        //返回
        StartProcessResp resp = new StartProcessResp();
        resp.setTaskId(currentTask.getId());
        resp.setBusinessKey(instance.getBusinessKey());
        resp.setProcessInstanceId(instance.getProcessInstanceId());
        log.info("{}的流程已启动，下一个节点{}", resp.getBusinessKey(), resp.getTaskId());
    	map.put("ret", "0");
		map.put("msg", "流程启动成功");
		map.put("data", resp);
        return ResponseEntity.ok(map);
	}

	/**
	 * 获取当前流程节点
	 * 
	 * @param businessKey
	 * @return
	 */
	@GetMapping(value = "/getCurrActivity/{businessKey}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Object> getCurrActivity(@PathVariable("businessKey") String businessKey) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Assert.hasLength(businessKey, "业务主键编号(businessKey)不能为空");
			// 检查流程是否已启动
			List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).list();
			CurrentTaskResp resp = new CurrentTaskResp();
			if (CollectionUtils.isEmpty(historicProcessInstances)) {
				logger.error("当前业务编号：{}未启动过流程！", businessKey);
				/*map.put("ret", "10400010");
				map.put("msg", "当前业务编号：" + businessKey + "未启动过流程！");*/
				map.put("ret", "0");
				map.put("msg", "当前业务编号：" + businessKey + "未启动过流程！");
				resp.setBusinessKey(businessKey);
				resp.setCurrActivityId("start");
				resp.setCurrActivityName("开始");
				map.put("data", resp);
				return ResponseEntity.ok(map);
			}
			// 获取当前节点taskId
			Task currentTask = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
			if (ObjectUtils.isEmpty(currentTask)) {
				logger.error("当前业务编号：{}已结束流程！", businessKey);
				/*map.put("ret", "10400020");
				map.put("msg", "当前业务编号：" + businessKey + "已结束流程！");*/
				map.put("ret", "0");
				map.put("msg", "当前业务编号：" + businessKey + "已结束流程！");
				resp.setBusinessKey(businessKey);
				resp.setCurrActivityId("end");
				resp.setCurrActivityName("结束");
				map.put("data", resp);
				return ResponseEntity.ok(map);
			} else {
				map.put("ret", "0");
				map.put("msg", "获取当前节点成功！");
				resp.setBusinessKey(businessKey);
				resp.setCurrActivityId(currentTask.getTaskDefinitionKey());
				resp.setCurrActivityName(currentTask.getName());
				resp.setProcessInstanceId(currentTask.getProcessInstanceId());
				resp.setTaskId(currentTask.getId());
				map.put("data", resp);
				return ResponseEntity.ok(map);
			}
		} catch (Exception e) {
			logger.error("获取当前流程节点异常，" + e.getMessage(), e);
			map.put("ret", "104000000");
			map.put("msg", "获取当前流程节点异常！");
			return ResponseEntity.ok(map);
		}
	}

	/**
	 * 自定义提交流程
	 * 
	 * @param submitProcessReq
	 * @return
	 */
	@PostMapping(value = "/submitProcess", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Object> submitProcess(@Valid @RequestBody SubmitProcessReq submitProcessReq) {
		Map<String, Object> map = new HashMap<String, Object>();
		Map<String, Object> variables = new HashMap<String, Object>();
		// 默认为通过
		if (StringUtils.isEmpty(submitProcessReq.getResult())) {
			submitProcessReq.setResult(VerificationType.approved.name());
		}
		// Assert.isTrue(AppUtils.isInType(VerificationType.class, submitProcessReq.getResult()), "验证结果类型(result)错误");
		VerificationType verificationType = VerificationType.valueOf(submitProcessReq.getResult());

		// 结束当前节点的变量
		variables.put("result", verificationType.name());
		
		String businessKey=submitProcessReq.getBusinessKey();
		
		// 检查流程是否已启动
		List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(submitProcessReq.getBusinessKey()).list();
		if (CollectionUtils.isEmpty(historicProcessInstances)) {
			logger.error("当前业务编号：{}未启动过流程！", businessKey);
			map.put("ret", "10400010");
			map.put("msg", "当前业务编号：" + businessKey + "未启动过流程！");
			return ResponseEntity.ok(map);
		}

		// 检查流程是否已结束
		Task currentTask = taskService.createTaskQuery().processInstanceBusinessKey(submitProcessReq.getBusinessKey()).singleResult();
		
		String taskId=submitProcessReq.getTaskId();
		
		if (ObjectUtils.isEmpty(currentTask)) {
			logger.error("当前业务编号：{}已结束流程！", businessKey);
			map.put("ret", "10400020");
			map.put("msg", "当前业务编号：" + businessKey + "已结束流程！");
			return ResponseEntity.ok(map);
		} else {
			// 参数的节点ID和当前节点ID不符合
			if (!StringUtils.isEmpty(submitProcessReq.getTaskId())&& !currentTask.getId().equals(submitProcessReq.getTaskId())) {
				logger.error("当前业务编号：{}对应taskId：{}不符！", businessKey, taskId);
				map.put("ret", "10400040");
				map.put("msg", "当前业务编号：" + businessKey + "对应taskId：" + taskId + "不符！");
				return ResponseEntity.ok(map);
			}
			//用此方法作为结束专用，触发ApplyTaskCompleteListener监听更新为流程结束
			taskService.complete(currentTask.getId(), variables);
			log.info("{}的任务{}已结束", submitProcessReq.getBusinessKey(), submitProcessReq.getTaskId());
			map.put("ret", "0");
			map.put("msg", "业务编号" + businessKey + "节点"+currentTask.getName()+"提交成功!");
		}
		return ResponseEntity.ok(map);
	}
	
	/**
	 * 手动结束流程
	 * 
	 * @param businessKey
	 * @param taskId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/completeProcess", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Object> completeProcess(@Valid @RequestBody CompleteProcessReq completeProcessReq) {
		String businessKey =completeProcessReq.getBusinessKey();
		String taskId = completeProcessReq.getTaskId();
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
			if (ObjectUtils.isEmpty(instance)) {
				logger.error("当前业务编号：{}未启动过流程！", businessKey);
				map.put("ret", "10400010");
				map.put("msg", "当前业务编号：" + businessKey + "未启动过流程！");
				return ResponseEntity.ok(map);
			}
			// 检查流程是否已结束
			Task completeTask = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
			if (ObjectUtils.isEmpty(completeTask)) {
				logger.error("当前业务编号：{}已结束流程！", businessKey);
				map.put("ret", "10400020");
				map.put("msg", "当前业务编号：" + businessKey + "已结束流程！");
				return ResponseEntity.ok(map);
			} else {
				// 参数的节点ID和当前节点ID不符合
				if (!StringUtils.isEmpty(taskId)&& !completeTask.getId().equals(taskId)) {
					logger.error("当前业务编号：{}对应taskId：{}不符！", businessKey, taskId);
					map.put("ret", "10400040");
					map.put("msg", "当前业务编号：" + businessKey + "对应taskId：" + taskId + "不符！");
					return ResponseEntity.ok(map);
				}
				Map<String, Object> variables = new HashMap<String, Object>();
				variables.put("businessKey", businessKey);
				variables.put("currActivityId", completeTask.getTaskDefinitionKey());
				variables.put("currActivityName", completeTask.getName());
				variables.put("taskId", completeTask.getId());
				//用此方法作为结束专用，触发ApplyTaskCompleteListener监听更新为流程结束
				taskService.complete(completeTask.getId(), variables);
				log.info("{}的任务{}已结束", businessKey, taskId);
				map.put("ret", "0");
				map.put("msg", "成功");
			}
		} catch (Exception e) {
			logger.error("手动结束流程异常，" + e.getMessage(), e);
			map.put("ret", "104000000");
			map.put("msg", "结束流程异常！");
			return ResponseEntity.ok(map);
		}
		return ResponseEntity.ok(map);
	}

	/**
	 * 回退流程
	 * 
	 * @param businessKey
	 * @param taskId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/backProcess", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Object> backProcess(@Valid @RequestBody CompleteProcessReq completeProcessReq) {
		String businessKey =completeProcessReq.getBusinessKey();
		String taskId = completeProcessReq.getTaskId();
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			if (StringUtils.isEmpty(businessKey)) {
				logger.error("请求参数错误");
				map.put("ret", "10400000");
				map.put("msg", "请求参数错误");
				return ResponseEntity.ok(map);
			}
			HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
			if (null == instance) {
				logger.error("当前业务编号：{}未启动过流程！", businessKey);
				map.put("ret", "10400010");
				map.put("msg", "当前业务编号：" + businessKey + "未启动过流程！");
				return ResponseEntity.ok(map);
			}
			// 检查流程是否已结束
			Task completeTask = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
			if (ObjectUtils.isEmpty(completeTask)) {
				logger.error("当前业务编号：{}已结束流程！", businessKey);
				map.put("ret", "10400020");
				map.put("msg", "当前业务编号：" + businessKey + "已结束流程！");
				return ResponseEntity.ok(map);
			} else {
				// 参数的节点ID和当前节点ID不符合
				if (!StringUtils.isEmpty(taskId)&& !completeTask.getId().equals(taskId)) {
					logger.error("当前业务编号：{}对应taskId：{}不符！", businessKey, taskId);
					map.put("ret", "10400040");
					map.put("msg", "当前业务编号：" + businessKey + "对应taskId：" + taskId + "不符！");
					return ResponseEntity.ok(map);
				}
				String fromActivityId = "";
				ProcessDefinitionEntity processdef = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(completeTask.getProcessDefinitionId());
				String processdefKey = processdef.getKey();
				if ("loan_apply_process".equals(processdefKey)) {
					Map<String, Object> variables = new HashMap<String, Object>();
					variables.put("businessKey", businessKey);
					String currActivityId = completeTask.getTaskDefinitionKey();
					variables.put("currActivityId", currActivityId);
					variables.put("currActivityName", completeTask.getName());
					variables.put("taskId", completeTask.getId());
					variables.put("operate", CurrResultEnum.BACK.name());
					// 获取流程所有节点
//					List<> activitiList = processdef.getCategory();
//					fromActivityId = applyBusinessService.getFromActivityId(currActivityId, activitiList);
//					applyBusinessService.customerSubmit((TaskEntity) task, fromActivityId, variables);
					
					// 使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
//					String InstanceId = completeTask.getProcessInstanceId();
//					List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(InstanceId).list();

//					 得到正在执行的Activity的Id
//					List<String> activityIds = new ArrayList<>();
//					for (Execution exe : executions) {
//						List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
//						activityIds.addAll(ids);
//					}
					
				} else {
					logger.error("未匹配到对应工作流!");
					map.put("ret", "104000900");
					map.put("msg", "未匹配到对应工作流!");
					return ResponseEntity.ok(map);
				}
				map.put("ret", "0");
				map.put("msg", "业务编号" + businessKey + "回退到上个节点" + fromActivityId + "成功");
			}
		} catch (Exception e) {
			logger.error("回退流程节点异常，" + e.getMessage(), e);
			map.put("ret", "104000000");
			map.put("msg", "回退流程异常！");
			return ResponseEntity.ok(map);
		}
		return ResponseEntity.ok(map);
	}

}
